/*
 * 工具函数
 *
 * src/pl/plpython/plpy_util.c
 */

#include "postgres.h"

#include "mb/pg_wchar.h"
#include "plpy_elog.h"
#include "plpy_util.h"
#include "plpython.h"
#include "utils/memutils.h"

/*
 * 将 Python unicode 对象转换为 PostgreSQL 服务器编码中的 Python 字符串/字节对象。引用所有权传递给调用者。
 */
PyObject * PLyUnicode_Bytes(PyObject *fc_unicode)
{
	PyObject   *fc_bytes,
			   *fc_rv;
	char	   *fc_utf8string,
			   *fc_encoded;

	/* 首先使用 UTF-8 编码 Python unicode 对象。 */
	fc_bytes = PyUnicode_AsUTF8String(fc_unicode);
	if (fc_bytes == NULL)
		PLy_elog(ERROR, "could not convert Python Unicode object to bytes");

	fc_utf8string = PyBytes_AsString(fc_bytes);
	if (fc_utf8string == NULL)
	{
		Py_DECREF(fc_bytes);
		PLy_elog(ERROR, "could not extract bytes from encoded string");
	}

	/*
	 * 然后在必要时转换为服务器编码。
	 *
	 * PyUnicode_AsEncodedString 可以直接在服务器编码中编码对象，但 Python 不支持所有 PostgreSQL 支持的编码（EUC_TW 和 MULE_INTERNAL）。在 PLyUnicode_FromString 中使用 UTF-8 作为中介。
	 */
	if (GetDatabaseEncoding() != PG_UTF8)
	{
		PG_TRY();
		{
			fc_encoded = pg_any_to_server(fc_utf8string,
									   strlen(fc_utf8string),
									   PG_UTF8);
		}
		PG_CATCH();
		{
			Py_DECREF(fc_bytes);
			PG_RE_THROW();
		}
		PG_END_TRY();
	}
	else
		fc_encoded = fc_utf8string;

	/* 最后，在服务器编码中构建字节对象 */
	fc_rv = PyBytes_FromStringAndSize(fc_encoded, strlen(fc_encoded));

	/* 如果 pg_any_to_server 分配了内存，立即释放它 */
	if (fc_utf8string != fc_encoded)
		pfree(fc_encoded);

	Py_DECREF(fc_bytes);
	return fc_rv;
}

/*
 * 将 PostgreSQL 服务器编码中的 C 字符串转换为 Python unicode 对象。引用所有权传递给调用者。
 */
char * PLyUnicode_AsString(PyObject *fc_unicode)
{
	PyObject   *fc_o = PLyUnicode_Bytes(fc_unicode);
	char	   *fc_rv = pstrdup(PyBytes_AsString(fc_o));

	Py_XDECREF(fc_o);
	return fc_rv;
}

/*
 * Convert a C string in the PostgreSQL server encoding to a Python
 * unicode object.  Reference ownership is passed to the caller.
 */
PyObject * PLyUnicode_FromStringAndSize(const char *fc_s, Py_ssize_t fc_size)
{
	char	   *fc_utf8string;
	PyObject   *fc_o;

	fc_utf8string = pg_server_to_any(fc_s, fc_size, PG_UTF8);

	if (fc_utf8string == fc_s)
	{
		fc_o = PyUnicode_FromStringAndSize(fc_s, fc_size);
	}
	else
	{
		fc_o = PyUnicode_FromString(fc_utf8string);
		pfree(fc_utf8string);
	}

	return fc_o;
}

PyObject * PLyUnicode_FromString(const char *fc_s)
{
	return PLyUnicode_FromStringAndSize(fc_s, strlen(fc_s));
}
